package com.apes.framework.plugin.todo;

import com.alibaba.fastjson.JSON;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.ApesBean;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.fsm.FsmStateInstance;
import com.apes.framework.plugin.fsm.FsmStateInstanceRepository;
import com.apes.framework.plugin.fsm.core.FsmEngine;
import com.apes.framework.plugin.express.FuncAlias;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.JpaUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 待办服务
 *
 * @author xul
 * @create 2020-12-16 09:21
 **/
@Service
public class TodoTaskService extends DomainService {

    private final FsmStateInstanceRepository fsmStateInstanceRepository;
    private final TodoTaskRepository todoTaskRepository;
    private final TodoTaskBackupRepository backupRepository;

    public TodoTaskService(FsmStateInstanceRepository fsmStateInstanceRepository, TodoTaskRepository todoTaskRepository,
                           TodoTaskBackupRepository backupRepository) {
        this.fsmStateInstanceRepository = fsmStateInstanceRepository;
        this.todoTaskRepository = todoTaskRepository;
        this.backupRepository = backupRepository;
    }

    /**
     * 创建任务
     *
     * @param task
     */
    public void createTask(TodoTask task) {
        if (todoTaskRepository.findAll(JpaDsl.toCriteriaByEq(
                "aggregateType", task.getAggregateType(),
                "aggregateId", task.getAggregateId(),
                "whenMvel", task.getWhenMvel(),
                "userId", task.getUserId())).stream().count() > 0) {
            return;
        }
        /**保存**/
        task = todoTaskRepository.saveAndFlush(task);
        /**推送待办消息**/
        Map body = mapper("action", "createTask", "topic", "ws.todo", "message", convertTask(task));
        invoke("wf.message.publish", mapper("to", task.getUserId(), "body", body));
    }

    /**
     * 完成任务
     *
     * @param task
     */
    public void finishTask(TodoTask task) {
        /**变更状态**/
        task.setState(1);

        /**备份**/
        TodoTaskBackup taskBackup = new TodoTaskBackup();
        ReflectUtil.copyAll(task, taskBackup);
        backupRepository.saveAndFlush(taskBackup);

        /**推送待办消息**/
        Map body = mapper("action", "finishTask", "topic", "ws.todo", "message", convertTask(task));
        invoke("wf.message.publish", mapper("to", task.getUserId(), "body", body));

        /**删除**/
        todoTaskRepository.delete(task);
    }

    /**
     * 变更任务
     *
     * @param task
     */
    public void updateTask(TodoTask task) {
        /**保存**/
        task = todoTaskRepository.saveAndFlush(task);

        /**推送待办消息**/
        Map body = mapper("action", "updateTask", "topic", "ws.todo", "message", convertTask(task));
        invoke("wf.message.publish", mapper("to", task.getUserId(), "body", body));
    }

    /**
     * 查询待办列表
     **/
    public List<Map> todoList(SimpleRequest request) {
        Integer userId = request.get("userId");
        return todoTaskRepository.findAll(JpaDsl.toCriteriaByEq("userId", String.valueOf(userId)))
                .stream().map(task -> convertTask(task)).collect(Collectors.toList());
    }

    private Map convertTask(TodoTask task) {
        return mapper("taskId", task.getId(), "description", task.getDescription(), "createTime", task.getCreateDate(),
                "tags", task.getTags(), "expired", task.getExpired(), "content", JSON.parseObject(task.getPayload()),
                "businessKey", task.getAggregateId(), "businessTypeName", task.aggregateTypeName(),"businessType",task.getAggregateType(),
                "formId", task.formId());
    }

    /**
     * 创建待办
     * 使用：待办(用户, 状态实例, '待办描述', '经办', '车牌', 车牌, '手机', 手机, ...)
     **/
    @FuncAlias(name = "待办")
    public void todo(List<String> users, String fsmStateInstanceId, String description, String tags, Object... payload) {
        FsmStateInstance fsmStateInstance = fsmStateInstanceRepository.findOne(fsmStateInstanceId);
        String aggregateSimpleName = fsmStateInstance.getState().getFsmFlow().getBusinessType().getId();
        Class clazz = JpaUtil.getDomainClass(aggregateSimpleName);
        if (clazz == null) return;
        String aggregateType = clazz.getName();
        String aggregateId = fsmStateInstance.getFsmFlowInstance().getBusinessKey();
        Date expired = fsmStateInstance.getExpired();
        String whenMvel = fsmStateInstance.getEvent() != null ? fsmStateInstance.getEvent().getWhenMvel() : "";
        process(users, aggregateType, aggregateId, whenMvel, expired, description, tags, fsmStateInstance.getInitDeptId(), fsmStateInstanceId, payload);
    }

    /**
     * 创建待办
     *
     * @param users         用户列表
     * @param aggregateType 业务模型
     * @param aggregateId   业务单号
     * @param whenMvel      条件
     * @param expired       过期时间
     * @param description   描述
     * @param tags          标签
     * @param payload       消息体
     */
    public void process(List<String> users, String aggregateType, String aggregateId, String whenMvel, Date expired, String description, String tags, String initDeptId, String fsmStateInstanceId, Object... payload) {
        Object entity = JpaUtil.getRepository(aggregateType).findOne(aggregateId);
        if (entity == null) return;
        Map context = FsmEngine.getMerge(entity);
        String message = JSON.toJSONString(MapUtil.mapper(payload));
        todoTaskRepository.findAll(JpaDsl.toCriteriaByEq("aggregateType", aggregateType, "aggregateId", aggregateId, "state", 0)).stream().forEach(task -> {
            if (FsmEngine.eval(task.getWhenMvel(), context)) {
                if (task.getTags().equals(tags) && users.contains(task.getUserId())) {
                    task.setExpired(expired);
                    task.setDescription(description);
                    task.setPayload(message);
                    updateTask(task);
                    users.removeIf(userId -> userId.equals(task.getUserId()));
                }
            }
        });

        if (FsmEngine.eval(whenMvel, context) && users.size() > 0) {
            users.stream().forEach(userId -> {
                TodoTask task = new TodoTask();
                task.setDescription(description);
                task.setTags(tags);
                task.setPayload(message);
                task.setAggregateType(aggregateType);
                task.setAggregateId(aggregateId);
                task.setWhenMvel(whenMvel);
                task.setExpired(expired);
                task.setUserId(userId);
                task.setInitDeptId(initDeptId);
                task.setFsmStateInstanceId(fsmStateInstanceId);
                createTask(task);
            });
        }
    }

    /**
     * 完成任务
     *
     * @param entity 实体
     */
    public void finishTask(ApesBean entity) {
        if (entity == null) return;
        Map context = FsmEngine.getMerge(entity);
        todoTaskRepository.findAll(JpaDsl.toCriteriaByEq("aggregateType", entity.getClass().getName(), "aggregateId", JpaUtil.getIdToStr(entity), "state", 0)).stream().forEach(task -> {
            if (!FsmEngine.eval(task.getWhenMvel(), context)) {
                finishTask(task);
            }
        });
    }

    public void stopTask(ApesBean entity) {
        if (entity == null) return;
        todoTaskRepository.findAll(JpaDsl.toCriteriaByEq("aggregateType", entity.getClass().getName(), "aggregateId", JpaUtil.getIdToStr(entity), "state", 0)).stream().forEach(task -> {
            finishTask(task);
        });
    }

    public Map findTodoTask(SimpleRequest request) {
        String aggregateType = request.get("businessType");
        String businessKey = request.get("businessKey");
        Class clazz = JpaUtil.getDomainClass(aggregateType);
        if (clazz == null) return null;
        List<TodoTask> todoTasks = todoTaskRepository.findAll(JpaDsl.toCriteriaByEq("aggregateType", clazz.getName(), "aggregateId", businessKey, "tags", "经办", "state", 0)).stream().collect(Collectors.toList());
        if (todoTasks.isEmpty()) return null;
        StringBuilder sb = new StringBuilder();
        todoTasks.stream().filter(task -> task.getUserId() != null).forEach(task -> {
            if (sb.length() != 0) {
                sb.append(",");
            }
            List<Object> users = sendSynEvent("event:aut.user.findOne", MapUtil.mapper("id", Integer.parseInt(task.getUserId())));
            if (users != null && users.size() > 0 && users.get(0) != null) {
                String userName = ReflectUtil.getFieldValue(users.get(0), "name");
                sb.append(userName);
            }
        });
        TodoTask task = todoTasks.stream().findFirst().get();
        return MapUtil.mapper("businessDate", DateUtil.format(task.getCreateDate(), DateUtil.SHOW_DATETIME_FORMAT),
                "businessKey", businessKey, "businessType", aggregateType,
                "operate", task.getDescription(), "operator", sb.toString());
    }

    /**
     * 根据条件查询待办列表
     * @return
     */
    public List<Map> todoListFilters(List<Map> filters) {
        return todoTaskRepository.findAll(JpaDsl.toCriteria(filters))
                .stream().map(task -> convertTask(task)).collect(Collectors.toList());
    }

    /**
     * 根据行政部门编码查询待办列表
     * @return
     */
    public List<Map> todoListByBranch(List<String> branchIds) {
        return todoTaskRepository.findByDept(branchIds)
                .stream().map(task -> convertTask(task)).collect(Collectors.toList());
    }

    /**
     * 根据行政部门编码和单据类型单据状态查询待办列表
     * @return
     */
    public List<Map> todoListByBranchAndBusiness(List<String> branchIds,String aggregateType,String description) {
        return todoTaskRepository.findByDeptAndBusiness(branchIds,aggregateType,description)
                .stream().map(task -> convertTask(task)).collect(Collectors.toList());
    }

}
